const utils = require("../utils/utils");
const pinyin = require("pinyin");
const BuildMoudle = require("../module/BuildModule");
const path = require("path");
const walk = require("../utils/walk");
const Define = require("../define");

const ZHI_FU = "zhifu";
const REN_SHU = "renshu";
const TUO_GUAN = "tuoguan";
//局数
const MO_SHI = "moshi";
const DUI_JU = "duiju";
const JU_SHU = "jushu";

const GUI_ZE = "guize";
const DI_FEN = "difen";
const BEI_SHU = "beishu";
const JIE_SAN = "jiesan";

const LINE = "Line";
const ROOM_TYPE = "RoomType";
const PLAYER_RULE = "playerRule";
const PLAYER_COUNT = "playerCount";
const NEW_FUZHU = "fuzhu";

/**选项列数 */
const ROW_LEN = 3;

/**
 * 需要复制的字段，不操作直接复制数据
 */
const COPY_KEYS = [
    [
        /* "payType" , 'playerCount', 'playerRule' */
    ],
    ["gpsxianzhi"],
];

/**加减选项，发送数据的进率 */
const ACCURACY = {
    2017: {
        accuracy: 10000,
        addaccuracy: 0,
    },
};
/**过滤器 */
class Filter {
    static _unableOptionTea = [2021, 2022, 2017];
    static _unabelOption = [2019, 2020, 2021, 2022, 2017];
    /**
     * 不添加选项
     * @param {number} id
     * @returns {boolean}
     */
    static unabelOption(id, tea) {
        return tea ? this._unableOptionTea.indexOf(id) > -1 : this._unabelOption.indexOf(id) > -1;
    }

    static _walkUnAble = [JIE_SAN];
    /**
     * 选项组添加许可
     * @param {string} key
     */
    static walkAble(key) {
        return this._walkUnAble.indexOf(key) < 0;
    }

    static _playerKeys = [REN_SHU];
    static isPlayer(key) {
        return this._playerKeys.indexOf(key) > -1;
    }

    static _payKeys = [ZHI_FU];
    static isPayByKey(key) {
        return this._payKeys.indexOf(key) > -1;
    }

    static roundKeys = [MO_SHI, DUI_JU, JU_SHU];
    /**
     * @param {string} key
     * @returns
     */
    static isRound(key) {
        return this.roundKeys.indexOf(key) > -1;
    }

    /**
     * 底分过滤
     * @param {number[]} options
     */
    static walkAbleDiFen(options) {
        const len = options.length;
        if (len == 1 && options[0] == 2017) return false;
        return true;
    }

    /**
     * 节点写入权限检测
     * @param {*} node
     * @returns
     */
    static unabelWriteNode(node) {
        if (
            node.type == "radio" ||
            node.nodeName == "okut=" ||
            node.nodeName == "mq_2017='2017#" ||
            node.nodeName == "shaorenkaiju"
        ) {
            return true;
        }
        return false;
    }

    static _peopleids = [20, 21, 22];
    /**
     * 非人员id过滤
     * @param {number} id
     */
    static isNotPeople(id) {
        return this._peopleids.indexOf(id) < 0;
    }

    static _payIds = [10, 11];
    static isPay(id) {
        return this._payIds.indexOf(id) > -1;
    }

    static _changeUnable = [10, 11, 2019, 2020];
    /**
     * change字段中不需要处理
     * @param {number[]} ids
     */
    static unableChangeWrite(ids) {
        if (!ids) return false;
        for (let id of ids) {
            if (this._changeUnable.indexOf(id) > -1) {
                return true;
            }
        }
        return false;
    }
}

class RoomOptonBuilder {
    _isTea = false;

    get isNotTea() {
        return !this._isTea;
    }

    /**
     * 文件模版
     */
    _temp;

    /**
     * 老文件对象
     */
    _old;

    /**
     * 人数列表
     */
    _playerCountList = [20, 21, 22];

    /**
     * 索引映射
     */
    _idxMap = {};

    /**
     * 联动id
     */
    _linkageLevel = 30;

    _levelMap = {};

    /**单组多地区id */
    _mulitpleId = 0;

    dir;

    dirName;

    info;

    /**
     * @type {BuildMoudle}
     */
    module;

    constructor(isTea) {
        this._isTea = isTea;
    }

    /**
     *
     * @param {string} dir
     * @param {*} info
     * @param {BuildMoudle} mod
     * @returns
     */
    build(dir, info, mod) {
        this.init(dir, info, mod);
        this.computedMulitpleId();
        let result = this.createStruct();
        //创建不限显示的，但是要发给服务器的，支付，人数
        this.createPlayerCost(result);
        this.ruleCtrlsWalk(result);
        //复制通用选项
        this.copyValue(COPY_KEYS[1], result, false);
        this.createDiFenCtrls(result);
        this.changeCtrlWalk(result);
        this.lockCtrlWalk(result);
        if (!this._isTea) {
            this.removeLastLine(result);
        }
        this.proofreadNode(result);
        this.write(result);
    }

    init(dir, info, mod) {
        this.dir = dir;
        this.dirName = path.basename(this.dir);
        this.info = info;
        this.module = mod;

        const oldid = this.info.OldGameName ?? this.info.OldGameID;
        this._old = walk.dirWalkFiles(this.module.inputPath, this.getOldFileName(oldid));
        this._temp = walk.dirWalk(this.module.tempPath, Define.FILE_RULE);
    }

    write(result) {
        const name = path.basename(this.dir);
        let file = path.join(this.module.outputPath, name, Define.DIR_CONFIG, this.getNewFileName());
        utils.writeFile(file, result, false, true);
    }

    getOldFileName(id) {
        return [id + ".json"];
    }

    getNewFileName() {
        return this._isTea ? "GameTeaRule.json" : "GameRule.json";
    }

    getBody(struct) {
        return struct.categories[0];
    }

    /**
     * 获取联动id
     * @returns
     */
    getLinkageLevel() {
        const level = this._linkageLevel;
        this._linkageLevel++;
        return level;
    }

    /**
     * 获取选项节点
     * @param {*} result
     * @param {*} id
     */
    getNodeById(result, id, noFilter = false) {
        const body = this.getBody(result);
        const old = this.getOldOption(id);
        if (!old) {
            return null;
        }
        const nodeName = this.createNodeName(old.name);
        const select = this.createSelect(id);

        let rule;
        let list;
        for (let key in body) {
            rule = body[key];
            for (let index in rule.ctrls) {
                list = rule.ctrls[index];
                for (let option of list) {
                    const name = option.nodeName;
                    const linkageLevel = option.linkageLevel;
                    if (option.id == id || name == select || name == nodeName || linkageLevel == id) {
                        if (noFilter) {
                            return option;
                        }
                        if (Filter.unabelWriteNode(option)) return null;
                        return option;
                    }
                }
            }
        }
        return null;
    }

    /**
     * 获取节点所在行
     * @param {*} result
     * @param {*} id
     * @returns
     */
    getNodeRowById(result, id) {
        const body = this.getBody(result);
        const nodeName = this.createNodeName(this.getOldOption(id).name);
        const select = this.createSelect(id);

        let rule;
        let list;
        for (let key in body) {
            rule = body[key];
            for (let index in rule.ctrls) {
                list = rule.ctrls[index];
                for (let option of list) {
                    const name = option.nodeName;
                    const linkageLevel = option.linkageLevel;
                    if (name == select || name == nodeName || linkageLevel == id) {
                        return list;
                    }
                }
            }
        }
        return null;
    }

    /**
     * 遍历节点
     * @param {*} result
     * @param {(node:any,index:number,list:any[],struct:any)=>{}} call
     */
    walkNode(result, call) {
        const body = this.getBody(result);
        let rule;
        let list;
        for (let key in body) {
            rule = body[key];
            for (let index in rule.ctrls) {
                list = rule.ctrls[index];
                for (let i = 0; i < list.length; i++) {
                    let option = list[i];
                    call.call(this, option, i, list, rule);
                }
            }
        }
    }

    /**
     * 创建 键
     * @param {string} key
     */
    createKey(key) {
        if (this._idxMap[key] == undefined) {
            this._idxMap[key] = 0;
        }
        const r = `${this._idxMap[key]}${key}`;
        this._idxMap[key]++;
        return r;
    }

    /**
     * 键 索引
     * @param {string} key
     */
    getKeyIndex(key) {
        return this._idxMap[key] - 1 ?? 0;
    }

    /**
     * 遍历老配置old.default
     * @param {*} result
     */
    ruleCtrlsWalk(result) {
        const oldCtrls = this.getOldCtrls();
        let oldCtrl;
        let ids = Object.keys(oldCtrls);
        ids.sort((a, b) => {
            const p1 = oldCtrls[a]?.priority ?? 0;
            const p2 = oldCtrls[b]?.priority ?? 0;
            const flag = p1 == p2;
            return flag ? 0 : p1 > p2 ? -1 : 1;
        });
        for (let id of ids) {
            oldCtrl = oldCtrls[id];
            const key = this.createNodeName(oldCtrl.name);
            if (Filter.walkAble(key) && Filter.walkAbleDiFen(oldCtrl.options)) {
                if (Filter.isPlayer(key)) {
                    //创建人数
                    this.createPlayer(result);
                } else if (Filter.isRound(key)) {
                    //创建局数
                    this.createRound(result, key, `${id}`);
                } else if (Filter.isPayByKey(key)) {
                    if (!this._isTea) this.createCtrls(result, key, `${id}`);
                } else {
                    this.createCtrls(result, key, `${id}`);
                }
            }
        }
    }

    /**
     * 获取互斥的其他id
     * @param {*} ids
     * @returns 其他id
     */
    computedShow(ids) {
        if (!ids) return;
        let copyIds = [...ids];
        if (!copyIds.length) return;

        let show = [];
        let first = copyIds[0];
        let unSelect = first > 10000;
        if (unSelect) {
            first -= 10000;
            copyIds = copyIds.map((v) => {
                return v - 10000;
            });
        } else {
            let option = this.getOldOption(first);

            const onlytype = option.onlytype;
            if (onlytype != 0) {
                let options = this._old.option;

                let item;
                for (let key in options) {
                    item = options[key];
                    const id = +key;
                    if (item.onlytype == onlytype && copyIds.indexOf(id) < 0 && show.indexOf(id) < 0) {
                        show.push(id);
                    }
                }
            }
        }

        //非互斥联动锁，按钮选中要解锁
        if (unSelect && show.length < 1) {
            show = [...copyIds];
        }
        return show;
    }

    /**
     * @param {number} id
     * @returns {number}
     */
    createUnlinkageLevel(id) {
        return 10000 + id;
    }

    /**
     * 遍历老配置联动选项
     */
    lockCtrlWalk(result) {
        const lock = this.getOldLock();

        for (let related of lock) {
            const match = related.matchSelectOptions;
            const matchUn = related.matchUnSelectOptions;
            const lockoptions = related.lockoptions;
            const select = related.relatedoptions;
            const unselect = related.relatedCanceloptions;

            if (match != undefined) {
                for (let id of match) {
                    let node = this.getNodeById(result, id);
                    if (node) {
                        if (node.linkageLevel === undefined) {
                            node.linkageLevel = id;
                        }
                        if (node.unSelectlinkageLevel === undefined) {
                            node.unSelectlinkageLevel = this.createUnlinkageLevel(id);
                        }
                    }
                }
            }

            if (matchUn != undefined) {
                for (let id of matchUn) {
                    let node = this.getNodeById(result, id);
                    if (node) {
                        if (node.linkageLevel === undefined) {
                            node.linkageLevel = id;
                        }
                        if (node.unSelectlinkageLevel === undefined) {
                            node.unSelectlinkageLevel = this.createUnlinkageLevel(id);
                        }
                    }
                }
            }

            if (lockoptions != undefined) {
                for (let id of lockoptions) {
                    let node = this.getNodeById(result, id);
                    if (node) {
                        if (node.prohibit === undefined) node.prohibit = [];
                        if (node.show === undefined) node.show = [];
                        node.prohibitStyle = "lock";
                        if (match) {
                            node.prohibit = node.prohibit.concat(match);
                            node.show = this.computedShow(node.prohibit);
                        }
                        if (matchUn) {
                            let firstUn = matchUn[0];
                            if (Filter.isNotPeople(firstUn)) {
                                node.prohibitUnion = node.prohibit.concat(
                                    matchUn.map((v) => {
                                        return this.createUnlinkageLevel(v);
                                    })
                                );
                            } else {
                                node.prohibit = this.getOtherOnlyTypeIds(matchUn);
                            }
                            node.show = this.computedShow(node.prohibitUnion);
                        }
                    }
                }
            }

            if (select != undefined) {
                for (let id of select) {
                    let node = this.getNodeById(result, id);
                    if (node) {
                        if (!node.linkageLevel) node.linkageLevel = id;
                        if (!node.unSelectlinkageLevel) {
                            node.unSelectlinkageLevel = this.createUnlinkageLevel(id);
                        }
                        if (!node.linkSelect) {
                            node.linkSelect = [];
                        }
                        if (match) {
                            node.linkSelect = node.linkSelect.concat(match);
                        }
                        if (matchUn) {
                            node.linkSelect = node.linkSelect.concat(
                                matchUn.map((v) => {
                                    return this.createUnlinkageLevel(v);
                                })
                            );
                        }
                    }
                }
            }

            if (unselect != undefined) {
                for (let id of unselect) {
                    let node = this.getNodeById(result, id);
                    if (node) {
                        if (!node.linkageLevel) node.linkageLevel = id;
                        if (!node.unSelectlinkageLevel) {
                            node.unSelectlinkageLevel = this.createUnlinkageLevel(id);
                        }
                        if (!node.linkUnSelect) {
                            node.linkUnSelect = [];
                        }
                        if (match) {
                            node.linkUnSelect = node.linkUnSelect.concat(match);
                        }
                        if (matchUn) {
                            node.linkUnSelect = node.linkUnSelect.concat(
                                matchUn.map((v) => {
                                    return this.createUnlinkageLevel(v);
                                })
                            );
                        }
                    }
                }
            }
        }
    }

    /**
     * 变化差异值
     * @param {*} id
     * @param {*} ids
     * @returns
     */
    getChangeDiff(id, ids) {
        let ctrl = this.getOldDefaultById(id);
        const options = [...ctrl.options];
        let result = [];
        for (let cid of ids) {
            if (options.indexOf(cid) < 0) {
                result.push(cid);
            }
        }
        return result;
    }

    /**
     * 显示隐藏变化
     * @param {*} result
     */
    changeCtrlWalk(result) {
        const change = this._old.change;

        for (let related of change) {
            const match = related.matchSelectOptions;
            const matchUn = related.matchUnSelectOptions;
            const changeoptions = related.changeoptions;
            const changetype = related.changetype;

            if (
                (match && Filter.unableChangeWrite(match)) ||
                (matchUn && Filter.unableChangeWrite(matchUn))
            ) {
                continue;
            }

            if (match != undefined) {
                for (let id of match) {
                    let node = this.getNodeById(result, id);
                    if (node) {
                        if (node.linkageLevel === undefined) {
                            node.linkageLevel = id;
                        }
                        if (node.unSelectlinkageLevel === undefined) {
                            node.unSelectlinkageLevel = this.createUnlinkageLevel(id);
                        }
                    }
                }
            }

            if (matchUn != undefined) {
                for (let id of matchUn) {
                    let node = this.getNodeById(result, id);
                    if (node) {
                        if (node.linkageLevel === undefined) {
                            node.linkageLevel = id;
                        }
                        if (node.unSelectlinkageLevel === undefined) {
                            node.unSelectlinkageLevel = this.createUnlinkageLevel(id);
                        }
                    }
                }
            }

            if (changeoptions != undefined) {
                let diff = this.getChangeDiff(changetype, changeoptions);
                for (let id of diff) {
                    let node = this.getNodeById(result, id, true);
                    if (node) {
                        if (node.show == undefined) node.show = [];
                        if (node.hide == undefined) node.hide = [];
                        if (match) {
                            node.show = node.show.concat(match);
                            node.hide = node.hide.concat(
                                match.map((v) => {
                                    return this.createUnlinkageLevel(v);
                                })
                            );
                        }
                        if (matchUn) {
                            node.show = node.show.concat(
                                matchUn.map((v) => {
                                    return this.createUnlinkageLevel(v);
                                })
                            );
                            node.hide = node.hide.concat(matchUn);
                        }
                        node.bindparent = true;
                    }
                }
            }
        }

        this.walkNode(result, function (node, index, row) {
            const id = node.id;
            if (id) {
                if (
                    row.some(function (v) {
                        return !v.bindparent;
                    })
                ) {
                    delete node.bindparent;
                }
            }
        });
    }

    /**
     * 计算单组多地区id
     */
    computedMulitpleId() {
        const list = this.dirName.split("_");
        if (list && list.length > 2) {
            const id = list[2];
            this._mulitpleId = parseInt(id);
        }
    }

    /**
     * 总结构
     * @returns
     */
    createStruct() {
        const struct = this._isTea ? { VirtualGameRuleID: this._mulitpleId } : {};
        const normal = {
            defaultchoose: 0,
            isCostRelativePlayers: true,
            showCostType: 1,
            categories: [{}],
        };
        return Object.assign(struct, normal);
    }

    /**
     * 复制选项
     * @param {*} keys
     * @param {*} struct
     */
    copyValue(keys, struct) {
        let body = this.getBody(struct);
        let temp = this._temp.categories[0];
        let tKeys = Object.keys(temp);
        for (let key of keys) {
            for (let i = 0; i < tKeys.length; i++) {
                let tKey = tKeys[i];
                if (tKey.search(key) > -1) {
                    body[tKey] = temp[tKey];
                    this.createLine(struct);
                }
            }
        }
    }

    /**
     * 创建底分节点
     * @returns
     */
    createDiFen(bodyName) {
        let old = this.getOldOption(2017);
        const nums = old.interval ?? [
            0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
        ];
        const name = old.name ?? "底分";
        const idx = nums.indexOf(old.intervalDefaultValue);
        return {
            text: bodyName ?? "底分",
            type: "fraction",
            nodeName: "difen",
            defaultchoose: ["1"],
            ctrls: {
                1: [
                    {
                        nodeName: "mq_2017='2017#",
                        nums: nums,
                        sourceidx: idx,
                        suffixStr: "';",
                        text: bodyName ?? "底分",
                        accuracy: 10000,
                        addaccuracy: 0,
                        bindparent: true,
                    },
                ],
            },
        };
    }

    /**
     * 底分创建
     * @param {*} result
     */
    createDiFenCtrls(result) {
        const old = this.findOldCtrlByKey(DI_FEN, BEI_SHU);
        if (old && old.options && old.options.length > 0 && old.options[0] == 2017) {
            const body = this.getBody(result);
            const key = this.createKey(DI_FEN);
            body[key] = this.createDiFen(old.name);
            this.createLine(result);
        }
    }

    createLine(struct) {
        const obj = struct.categories[0];
        let lineKey = this.createKey(LINE);
        obj[lineKey] = {
            nodeName: "line_" + this.getKeyIndex(LINE),
            type: "line",
        };
    }

    /**
     * 创建选项结构体
     * @param {string} name
     * @param {number[]} defaultchoose
     * @returns
     */
    createRuleBody(name, defaultchoose = []) {
        const struct = {
            text: name,
            type: "checkbox",
            columnsPerRow: ROW_LEN,
            defaultchoose: defaultchoose,
        };
        if (name != undefined) {
            struct.nodeName = this.createNodeName(name);
        }
        struct.ctrls = {};
        return struct;
    }

    /**
     * 离线踢出房间
     * @returns
     */
    createOffline() {
        return {
            nodeName: "offlineleave",
            haveTips: "开局前，玩家离线超过一定时长自动踢出房间",
            select: "mp=1;",
            unselect: "",
            text: "离线踢出房间",
            linkageLevel: 5,
            unSelectlinkageLevel: 6,
            onlyAutoRoom: true,
        };
    }

    /**
     * 离线时长
     * @returns
     */
    createOfflineTime(stepx = 0) {
        const old = this.getOldOption(2019);
        const nums = old.interval ?? [0, 5, 30, 60, 90, 120, 150];
        const idx = nums.indexOf(old.intervalDefaultValue);
        return {
            type: "fraction",
            nodeName: "okut=",
            sourceidx: 0,
            nums: old.interval ?? [0, 5, 30, 60, 90, 120, 150],
            sourceidx: idx,
            suffixStr: ";",
            accuracy: 1,
            addaccuracy: 0,
            show: [5],
            hide: [6],
            bindparent: true,
            leftText: "时长",
            rightText: "秒",
            onlyAutoRoom: true,
            StepX: stepx,
        };
    }

    /**
     * 占位配置
     * @returns
     */
    createEmpty() {
        return { type: "empty", onlyAutoRoom: true };
    }

    /**
     * 创建选中值
     * @param {number} id
     * @returns
     */
    createSelect(id) {
        return `mq_${id}='${id}';`;
    }

    getDisplayStyle(id) {
        return Filter.isPay(id) ? "circle" : "square";
    }

    /**
     * 创建单个选项
     * @param {number} id
     * @param {string} text
     * @param {number} onlytype
     * @returns
     */
    createOption(id, text, onlytype, ...params) {
        const select = Filter.isPay(+id) ? `payType=${+id - 10};` : `mq_${id}='${id}';`;
        const old = this.getOldOption(id);
        const option = {
            id: id,
            nodeName: this.createNodeName(text),
            text: text,
            select: select,
            unselect: "",
        };

        if (old && old.help) {
            option.haveTips = old.help;
        }

        /**老配置中有新配置未实现的选项，不添加到新配置 */
        if (Filter.unabelOption(id, this._isTea) || !text) {
            return null;
        }
        //同网络
        if (id == 10) {
            option.costType = "allCost";
        } else if (id == 11) {
            option.costType = "aaCost";
        } else if (id == 2004) {
            option.nodeName = "ipforbid";
            option.select = "iplimit='1';";
        } else if (id == 2006) {
            return this.createOptionShaoRen();
        } else if (id == 1585) {
            if (this._isTea) {
                option.linkageLevel = 7;
                option.unSelectlinkageLevel = 8;
            }
        } else if (id == 2020) {
            return this.createOffline();
        } else if (id == 2019) {
            return this.createOfflineTime(params[0]);
        }

        if (onlytype != 0 && onlytype != undefined) {
            option.linkageLevel = id;
            option.unSelectlinkageLevel = this.createUnlinkageLevel(id);
            if (onlytype < 0) {
                option.linkUnSelect = this.computedShow([id]);
            } else {
                option.nodeName = select;
                option.type = "radio";
                option.displayStyle = this.getDisplayStyle(id);
                option.parent = `mq_radio_parent_${onlytype < 0 ? onlytype * -100 : onlytype}`;
                delete option.select;
                delete option.unselect;
            }
        }
        if (old.interval) {
            this.createInterval(id, option);
        }
        return option;
    }

    /**
     * 加减选项
     * @param {*} id
     * @param {*} source
     */
    createInterval(id, source) {
        const old = this.getOldOption(id);
        const acc = ACCURACY[id] ?? { accuracy: 1, addaccuracy: 0 };
        const idx = old.intervalDefaultValue ? old.interval.indexOf(old.intervalDefaultValue) : 0;

        const option = {
            nodeName: `mq_${id}='${id}#`,
            type: "fraction",
            text: old.text,
            nums: old.interval,
            sourceidx: idx,
            suffixStr: ";",
            accuracy: acc.accuracy,
            addaccuracy: acc.addaccuracy,
        };

        if (old.beforeName) {
            delete option.text;
            delete source.text;
            option.leftText = old.beforeName;
            option.rightText = old.name;
        }

        Object.assign(source, option);
    }

    /**
     * 少人开局
     * @returns
     */
    createOptionShaoRen() {
        const list = utils.copyObj(this._playerCountList);
        const teaParams = { needRecoverStatus: true };
        const struct = {
            nodeName: "shaorenkaiju",
            select: "mq_2006='2006';",
            unselect: "",
            text: "可少人开局",
            show: [list[1], list[2]],
            linkSelect: [list[1], list[2]],
            prohibit: [list[0]],
            prohibitStyle: "lock",
        };
        return this._isTea ? Object.assign(teaParams, struct) : struct;
    }

    createNodeName(name) {
        let pin = pinyin(name, { style: pinyin.STYLE_NORMAL });
        let str = "";
        for (let p of pin) {
            str += p[0].trim();
        }
        return str;
    }

    /**
     * 纠错茶馆辅助选项
     */
    proofreadFuzhuOldOptions(options) {
        // if (options.indexOf(1585) < 0) {
        //     options.push(1585);
        // }

        if (options.indexOf(2020) > -1) {
            let i = options.indexOf(2020);
            const id = options.splice(i, 1)[0];
            options.push(id);
        }

        if (options.indexOf(2019) > -1) {
            let i = options.indexOf(2019);
            const id = options.splice(i, 1)[0];
            options.push(id);
        }
    }

    /**
     * 索引选项
     * @param {any[]} list 选项列表
     * @param {string} name
     * @returns
     */
    indexOfNodeName(list, name) {
        if (list && list.length > 0) {
            for (let i = 0; i < list.length; i++) {
                let item = list[i];
                if (item.nodeName == name) {
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     * 创建玩法规则
     * @param {*} result
     * @param {string} newKey 自定义键
     * @param {string} oldDefaulId 组id 例如：规则组 id字段
     */
    createCtrls(result, newKey, oldDefaulId) {
        const body = this.getBody(result);
        let cur = this.getOldDefaultById(oldDefaulId);
        if (cur) {
            //创建规则结构体
            let key = this.createKey(newKey);
            let roomTypeBody = this.createRuleBody(cur.name);
            const ctrls = roomTypeBody.ctrls;
            body[key] = roomTypeBody;
            //设置默认选中项
            let defaults = [];
            let option;
            for (let d of cur.defaults) {
                option = this.getOldOption(d);
                if (option) {
                    defaults.push(this.createOption(d, option.name, option.onlytype).nodeName);
                }
            }
            roomTypeBody.defaultchoose = defaults;
            //创建选项
            const oldOptions = this.createChangeList(oldDefaulId);
            if (newKey == NEW_FUZHU) {
                this.proofreadFuzhuOldOptions(oldOptions);
            }
            let col = 1;
            for (let i = 0; i < oldOptions.length; i++) {
                let oldId = oldOptions[i];
                option = this.getOldOption(oldId);
                if (option) {
                    if (!ctrls[col]) {
                        ctrls[col] = [];
                    }
                    let rowList = ctrls[col];
                    if (rowList.length >= ROW_LEN) {
                        col++;
                        if (!ctrls[col]) {
                            ctrls[col] = [];
                        }
                        rowList = ctrls[col];
                    }
                    let newOption = this.createOption(oldId, option.name, option.onlytype);
                    if (newOption) {
                        if (oldId == 2019) {
                            if (rowList.length > 0) {
                                col++;
                                ctrls[col] = [];
                                rowList = ctrls[col];
                            }
                            const emptyLen = this.indexOfNodeName(ctrls[col - 1], "offlineleave");
                            if (emptyLen > -1) {
                                newOption = this.createOption(oldId, option.name, option.onlytype, emptyLen);
                            }
                        }
                        rowList.push(newOption);
                        if (oldId == 2020) {
                            if (rowList.length == ROW_LEN) newOption.tipsStyle = "right";
                        }
                    }
                }
            }
        }
        this.createLine(result);
    }

    /**
     * 获取有显示变化的选项列表总列表
     * 包括所有默认 显示/不显示 的选项
     */
    createChangeList(id) {
        let changes = this.getOldChangeById(id);
        let ctrls = this.getOldDefaultById(id);
        let options = [...ctrls.options];
        let list = options;
        for (let change of changes) {
            let temp = [...change.changeoptions].concat(list);
            for (let itemId of temp) {
                if (list.indexOf(itemId) < 0) {
                    list.push(itemId);
                }
            }
        }
        return list;
    }

    /**
     * 创建人数
     * @param {*} value
     */
    createPlayerCtrl(value, id) {
        let obj = {
            nodeName: `playerCount_${value}`,
            text: `${value}人`,
            linkageLevel: id,
            // unSelectlinkageLevel: this.createUnlinkageLevel(id),
        };
        if (value == 2 || id == 20) {
            obj.tagName = "hot";
        }
        return obj;
    }

    /**
     * 创建默认人数，支付
     * @param {*} result
     */
    createPlayerCost(result) {
        const body = this.getBody(result);
        let oldPay = this.findOldCtrlByKey(ZHI_FU);
        let oldRen = this.findOldCtrlByKey(REN_SHU);

        if (!this._isTea && !oldPay) {
            let payKey = this.createKey(ZHI_FU);
            body[payKey] = {
                text: "支付",
                nodeName: "costType",
                type: "radio",
                columnsPerRow: 3,
                defaultchoose: ["payType=0;"],
                ignoreActive: true,
                hideNode: true,
                ctrls: {
                    1: [
                        {
                            nodeName: "payType=0;",
                            costType: "allCost",
                            text: "房主支付",
                            bindparent: true,
                        },
                    ],
                },
            };
        }

        if (!oldRen) {
            let renKey = this.createKey(REN_SHU);
            body[renKey] = {
                text: "人数",
                nodeName: "playerCount",
                columnsPerRow: 3,
                type: "radio",
                defaultchoose: ["playerCount_5"],
                ignoreActive: true,
                hideNode: true,
                ctrls: {
                    1: [
                        {
                            nodeName: "playerCount_5",
                            text: "5人",
                            linkageLevel: 2,
                            bindparent: true,
                        },
                    ],
                },
            };
        }
    }

    /**
     * 创建人数和局数
     * @param {*} result
     */
    createPlayer(result) {
        const body = this.getBody(result);
        //人数
        let playerCountBody = this.createRuleBody("人数");
        playerCountBody.nodeName = "playerCount";
        playerCountBody.type = "radio";
        playerCountBody.ctrls = { 1: [] };

        body[`1${PLAYER_COUNT}`] = playerCountBody;

        let oldStruct = this.findOldCtrlByKey(REN_SHU);
        if (!oldStruct) return;
        let oldCtrls = oldStruct.options;
        let defaults = [];
        let id;
        this._playerCountList = [];
        for (let i = 0; i < oldCtrls.length; i++) {
            id = oldCtrls[i];
            let option = this.getOldOption(id);
            let value = this.getOldOptionCount(option.name);
            this._playerCountList.push(id);
            let ctrl = this.createPlayerCtrl(value, id);
            playerCountBody.ctrls["1"].push(ctrl);
            //检测老配置默认选中，添加到新配置默认选中列表中
            if (oldStruct.defaults.indexOf(id) > -1) {
                defaults.push(ctrl.nodeName);
            }
        }
        playerCountBody.defaultchoose = defaults;
        this.createLine(result);
    }

    /**
     * 人数结构体
     * @param {number} value 人数
     */
    createRoundStruct(count, id) {
        let countList = [...this._playerCountList] ?? [20, 21, 22];
        let show;
        for (let i = 0; i < countList.length; i++) {
            if (count == countList[i] || id == countList[i]) {
                show = countList.splice(i, 1);
                break;
            }
        }
        return {
            text: "局数",
            nodeName: `playCount${count - 1}`,
            type: "radio",
            defaultchoose: [],
            show: show,
            hide: countList,
            bindparent: true,
            ctrls: {},
        };
    }

    /**
     * 创建局数键
     * @returns
     */
    createRoundKey() {
        return this.createKey(PLAYER_RULE);
    }

    /**
     * 创建局数
     * @param {*} result
     */
    createRound(result, key, groupid) {
        const body = this.getBody(result);
        /**@type {number[]} */
        let playerOptions = this.findOldCtrlByKey(REN_SHU)?.options ?? [];

        if (playerOptions.length == 0) {
            this.createRoundWithoutPlayer(result);
            return;
        }

        //老配置默认选中索引
        const oldIndex = this.getOldRoundDefaultSelectIndex();

        let roundBody;
        let ctrls;
        let id;
        for (let i = 0; i < playerOptions.length; i++) {
            id = playerOptions[i];
            let oldPlayer = this.getOldOption(id);
            let count = this.getOldOptionCount(oldPlayer.name);
            //创建局数结构体
            roundBody = this.createRoundStruct(count, id);
            ctrls = roundBody.ctrls;
            body[this.createRoundKey()] = roundBody;
            //获取老配置局数消耗数据
            //房主支付
            let oldMatchSelect = this.findOldChangeByMatchSelectId(10, id);
            if (!oldMatchSelect) oldMatchSelect = this.findOldChangeByMatchSelectId(id);
            //aa支付
            let oldMatchSelectAA = this.findOldChangeByMatchSelectId(11, id);
            if (!oldMatchSelectAA) oldMatchSelectAA = this.findOldChangeByMatchSelectId(id);
            let oldChangeOptions = oldMatchSelect.changeoptions;
            let oldChangeOptionsAA = oldMatchSelectAA.changeoptions;
            let col = 1;
            let defaultchoose = [];
            for (let j = 0; j < oldChangeOptions.length; j++) {
                let oldOptionId = oldChangeOptions[j];
                let oldOptionIdAA = oldChangeOptionsAA[j];
                let oldOptionName = this.getOldOption(oldOptionId).name;
                let oldOptionNameAA = this.getOldOption(oldOptionIdAA).name;
                if (!oldOptionName || !oldOptionNameAA) continue;
                //老配置局数消耗映射
                let data = this.parseOldRoundString(oldOptionName);
                let dataAA = this.parseOldRoundString(oldOptionNameAA);
                if (!data || !dataAA) continue;
                //创建新选项
                let nodeName = "round_type='" + data.roundType + "';round='" + data.round + "';";
                if (j == oldIndex) {
                    defaultchoose.push(nodeName);
                    roundBody.defaultchoose = defaultchoose;
                }
                let newRoundOption = {
                    nodeName: nodeName,
                    text: data.name,
                    allCost: data.cost + "",
                    aaCost: dataAA.cost + "",
                    [`allCost${count}`]: data.cost + "",
                    [`aaCost${count}`]: dataAA.cost + "",
                };
                if (!ctrls[col]) {
                    ctrls[col] = [];
                }
                let rowList = ctrls[col];
                if (rowList.length >= ROW_LEN) {
                    col++;
                    ctrls[col] = [];
                    rowList = ctrls[col];
                }
                rowList.push(newRoundOption);
            }
        }

        this.createLine(result);
    }

    /**
     * 创建局数 无人数选项时候
     * @param {*} result
     */
    createRoundWithoutPlayer(result) {
        const body = this.getBody(result);
        const oldDefault = this.findOldCtrlByKey(...Filter.roundKeys);

        if (oldDefault) {
            const roundBody = {
                text: "局数",
                nodeName: `playCount1`,
                type: "radio",
                defaultchoose: [],
                // show: show,
                // hide: countList,
                bindparent: true,
                ctrls: {},
            };
            body[this.createRoundKey()] = roundBody;

            const oldOptions = oldDefault.options;
            let oldId;
            let ctrls = roundBody.ctrls;
            let col = 1;
            for (let i = 0; i < oldOptions.length; i++) {
                oldId = oldOptions[i];
                let oldOption = this.getOldOption(oldId);
                if (!oldOption) continue;
                let data = this.parseOldRoundString(oldOption.name);
                if (!data) continue;
                //创建新选项
                let nodeName = "round_type='" + data.roundType + "';round='" + data.round + "';";
                if (oldDefault.defaults && oldDefault.defaults.indexOf(oldId) > -1) {
                    roundBody.defaultchoose.push(nodeName);
                }
                const cost = data.cost + "";
                let costAA = cost;
                const aaList = this.findOldChangeByMatchSelectId(11);
                if (aaList) {
                    let oldOptionAA = this.getOldOption(aaList.changeoptions[i]);
                    costAA = this.parseOldRoundString(oldOptionAA.name).cost + "";
                }
                let newRoundOption = {
                    nodeName: nodeName,
                    text: data.name,
                    allCost: cost,
                    allCost2: cost,
                    allCost3: cost,
                    allCost4: cost,
                    allCost5: cost,
                    aaCost: costAA,
                    aaCost2: costAA,
                    aaCost3: costAA,
                    aaCost4: costAA,
                    aaCost5: costAA,
                };
                if (!ctrls[col]) {
                    ctrls[col] = [];
                }
                let rowList = ctrls[col];
                if (rowList.length >= ROW_LEN) {
                    col++;
                    ctrls[col] = [];
                    rowList = ctrls[col];
                }
                rowList.push(newRoundOption);
            }
            this.createLine(result);
        }
    }

    /**
     * 删除选项中最后一个（线）字段
     * @param {*} result
     */
    removeLastLine(result) {
        const body = this.getBody(result);
        const keys = Object.keys(body);
        const len = keys.length;
        if (len > 0) {
            let last = keys[len - 1];
            if (last.search(LINE) > -1) {
                delete body[last];
            }
        }
    }

    /**
     * 生成完成后
     * 校对节点数据
     */
    proofreadNode(result) {
        this.walkNode(result, function (node, index, row, rule) {
            if (rule.nodeName == ZHI_FU) {
                rule.nodeName = "costType";
            }

            if (node.haveTips) {
                if (index == ROW_LEN - 1) {
                    node.tipsStyle = "right";
                }
            }

            if (node.prohibitUnion) {
                if (node.prohibitUnion.length < 2) {
                    delete node.prohibitUnion;
                } else if (node.prohibitUnion.length >= 2) {
                    delete node.prohibit;
                }
            }
        });
        this.walkNode(result, function (node, index) {
            const id = node.id;
            if (id) {
                delete node.id;
            }
        });
    }

    //-------------------------------------老配置操作接口----------------------------------------------
    /**
     * 老配置人数选项名字提取(人数)值或局数
     * @param {*} str
     */
    getOldOptionCount(str) {
        let rgx = /[0-9]{1,}/g;
        let strs = str.match(rgx);
        if (strs && strs.length) {
            return +strs[0];
        }
        return 0;
    }

    /**
     * 获取老配置中选项
     * @param {string|number} id
     * @returns
     */
    getOldOption(id) {
        if (typeof id == "number") id = id.toString();
        const old = this._old;
        let cur = old.option[id];
        if (!cur && id == 1585) {
            cur = {
                id: 1585,
                type: "6",
                name: "手动准备",
                onlytype: 0,
            };
        }
        return cur;
    }

    /**
     * 获取老配置全部选项
     * @returns
     */
    getOldCtrls() {
        return this._old.default;
    }

    /**
     * 根据拼音搜索选项组 guize=>规则结构体
     * @param {string[]} finds
     */
    findOldCtrlByKey(...finds) {
        let ctrls = this.getOldCtrls();
        let ctrl;
        for (let find of finds) {
            for (let key in ctrls) {
                ctrl = ctrls[key];
                if (ctrl && this.createNodeName(ctrl.name) == find) {
                    return ctrl;
                }
            }
        }
        return null;
    }

    /**
     * 寻找change中的数据
     * @param {number[]} ids
     * @returns
     */
    findOldChangeByMatchSelectId(...ids) {
        let change = this._old.change;
        let item;
        for (let i = 0; i < change.length; i++) {
            item = change[i];
            let match = item.matchSelectOptions;
            const yes =
                match &&
                ids.every((id) => {
                    return match.indexOf(id) > -1;
                });
            if (yes) {
                return item;
            }
        }
        return null;
    }

    /**
     * 解析局数字符串
     * @param {string} str
     * @returns
     */
    parseOldRoundString(str) {
        let texts = str.split("(");
        let name = texts[0];
        let round = this.getOldOptionCount(name);
        let roundType = name.indexOf("圈") > -1 ? 0 : 1;
        let cost = this.getOldOptionCount(texts[1]);
        let aa = texts[1].indexOf("人") > -1;
        return {
            name: name,
            round: round,
            roundType: roundType,
            cost: cost,
            aa: aa,
            costAA: 0,
        };
    }

    /**
     * 圈局房卡消耗映射
     */
    parseOldRoundMap() {
        let map = {};
        let options = this._old.option;
        let option;
        for (let key in options) {
            option = options[key];
            let name = option.name;
            if (name.indexOf("房卡") > -1) {
                let roundData = this.parseOldRoundString(name);
                let roundName = roundData.name;
                if (map[key]) {
                    if (roundData.aa) map[key].costAA = roundData.cost;
                } else {
                    map[key] = roundData;
                }
            }
        }
        return map;
    }

    /**
     * 获取局数默认选中索引值
     */
    getOldRoundDefaultSelectIndex() {
        let index = 0;
        let ctrl = this.findOldCtrlByKey(MO_SHI, DUI_JU);
        if (ctrl && ctrl.defaults && ctrl.defaults.length) {
            index = ctrl.options.indexOf(ctrl.defaults[0]);
        }
        return index;
    }

    /**
     * 老文件联动值
     * @returns
     */
    getOldLock() {
        return this._old.lock;
    }

    getOtherOnlyTypeIds(ids) {
        if (!ids) return;
        let copyIds = [...ids];
        if (!copyIds.length) return;

        const show = [];
        let first = copyIds[0];
        let unSelect = first > 10000;
        if (unSelect) {
            first -= 10000;
            copyIds = copyIds.map((v) => {
                return v - 10000;
            });
        }
        let option = this.getOldOption(first);

        const onlytype = option.onlytype;
        if (onlytype != 0) {
            let options = this._old.option;

            let item;
            for (let key in options) {
                item = options[key];
                const id = +key;
                if (item.onlytype == onlytype && copyIds.indexOf(id) < 0 && show.indexOf(id) < 0) {
                    show.push(id);
                }
            }
        }
        return show;
    }

    getOldChangeById(id) {
        const change = this._old.change;
        let list = [];
        for (let item of change) {
            let type = item.changetype;
            if (type == id || `${type}` == id) {
                list.push(item);
            }
        }
        return list;
    }

    getOldDefaultById(id) {
        let defaults = this._old.default;
        return defaults[`${id}`];
    }
}

module.exports = RoomOptonBuilder;
